/*
 * Copyright (c) 2020 hebeiyiliuba.com
 * All rights reserved.
 *
 */

package org.jeecg.modules.third.jg.report.freight.information.service;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.HexUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.exception.JeecgBootException;
import org.jeecg.common.util.MD5Util;
import org.jeecg.common.util.RedisUtil;
import org.jeecg.modules.third.jg.report.freight.information.constant.AhReportConstant;
import org.jeecg.modules.third.jg.report.freight.information.constant.ReportConstant;
import org.jeecg.modules.third.jg.report.freight.information.constant.TianjinReportConstant;
import org.jeecg.modules.third.jg.report.freight.information.constant.enums.ReportDocTypeEnum;
import org.jeecg.modules.third.jg.report.freight.information.dto.AppInfoDTO;
import org.jeecg.modules.third.jg.report.freight.information.model.TianjinReportModel;
import org.jeecg.modules.third.jg.report.information.dto.ResultDTO;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import zyb.cn.hutool.crypto.SmUtil;
import zyb.cn.hutool.crypto.asymmetric.KeyType;
import zyb.cn.hutool.crypto.asymmetric.SM2;

import javax.annotation.Resource;
import java.util.Date;
import java.util.UUID;

/**
 * @Description: 天津监管平台上报
 */
@Service
@Slf4j
public class TianjinReportPlatformService {

    @Resource
    private RedisUtil redisUtil;

    private String tjReportPlatformDomain;

    private String tjReportUsername;

    private String tjReportPassword;

    private String tjReportPublickey;

    private String appId;

    private String appSecurity;

    private String appSenderCode;

    private String appDebugSystem;

    public AppInfoDTO getAppInfo() {
        return AppInfoDTO.builder()
                .appId(this.appId)
                .appSecurity(this.appSecurity)
                .enterpriseSenderCode(this.appSenderCode)
                .debugSystem(this.appDebugSystem)
                .build();
    }

    public void setReportInfo(String reportPlatformDomain,
                              String username,
                              String password,
                              String publickey,
                              String appId,
                              String appSecurity,
                              String appSenderCode,
                              String appDebugSystem) {
        //联调状态的App需要设置debugSystem
        if ("0".equals(appDebugSystem)) {
            appDebugSystem = "debugSystem";
        }

        this.tjReportPlatformDomain = reportPlatformDomain;
        this.tjReportUsername = username;
        this.tjReportPassword = password;
        this.tjReportPublickey = publickey;
        this.appId = appId;
        this.appSecurity = appSecurity;
        this.appSenderCode = appSenderCode;
        this.appDebugSystem = appDebugSystem;
    }


    private String getLoginToken() {

        if (StrUtil.isEmpty(this.tjReportUsername) || StrUtil.isEmpty(this.tjReportPassword) || StrUtil.isEmpty(this.tjReportPublickey)) {
            throw new JeecgBootException("天津上报参数配置错误");
        }

        log.info("天津监管上报参数: {}, {}, {}", this.tjReportUsername, this.tjReportPassword, this.tjReportPublickey);

        Object tokenObject = redisUtil.get(TianjinReportConstant.API_REPORT_TOKEN_KEY + "_" + this.tjReportUsername);
        if (tokenObject != null){
            return tokenObject.toString();
        }

        JSONObject jsonObject = new JSONObject();
        jsonObject.put("userId", this.tjReportUsername);
        String realKey = MD5Util.MD5Encode(this.tjReportPassword, "utf-8");
        jsonObject.put("password", realKey.toLowerCase());
        String url = this.tjReportPlatformDomain + TianjinReportConstant.AUTH_URL;

        log.info("天津监管Token请求 -> {}", jsonObject.toJSONString());
        String authResult = HttpUtil.post(url, jsonObject.toJSONString());
        log.info("天津监管Token回执 <- {}", authResult);

        if (StrUtil.isNotEmpty(authResult)) {
            JSONObject resultObject = JSONObject.parseObject(authResult);
            //结果代码： “00000“代表本次请求响应正确
            if (resultObject.get("code") != null && resultObject.get("code").equals("00000")) {
                redisUtil.set(TianjinReportConstant.API_REPORT_TOKEN_KEY + "_" + this.tjReportUsername,
                        resultObject.get("token").toString(), TianjinReportConstant.API_REPORT_TOKEN_KEY_EXPIRE);
                return resultObject.get("token").toString();
            }
        }

        return null;
    }

    /**
     * 组装交换报文
     * @param reportDocTypeEnum 上报单据类型
     * @return
     */
    private TianjinReportModel messageAssembly(ReportDocTypeEnum reportDocTypeEnum, String xmlString) throws Exception {

        if (!ReportDocTypeEnum.isValid(reportDocTypeEnum.getCode()) || StrUtil.isEmpty(xmlString)){
            return null;
        }

        //获取监管平台Token
        String token = getLoginToken();
        if (StrUtil.isEmpty(token)){
            return null;
        }

        //因为天津SM2需要用到1.66+密码算法包和智运宝一样，所以这里SM2用的是智运宝（zyb）里的hutool，解决密码包版本冲突
        byte[] publicKeyBytes = HexUtil.decodeHex(this.tjReportPublickey);
        SM2 sm2 = SmUtil.sm2(null, publicKeyBytes);
        String encryptBase64 = sm2.encryptBcd(xmlString, KeyType.PublicKey);

        //组装交换报文
        return TianjinReportModel.builder()
                .UserId(this.tjReportUsername)
                .Token(token)
                .MessageReferenceNumber(UUID.randomUUID().toString().replace("-", ""))
                .DocumentName(reportDocTypeEnum.getMsg())
                .MessageSendingDateTime(DateUtil.format(new Date(), "yyyyMMddHHmmss"))
                .IPCType(reportDocTypeEnum.getCode())
                .EncryptedContent(encryptBase64)
                .build();
    }

    /**
     * 发送上报
     * @param reportDocTypeEnum
     * @param xmlString
     */
    public ResultDTO sendReport(ReportDocTypeEnum reportDocTypeEnum, String xmlString) throws Exception {

        TianjinReportModel tianjinReportModel = messageAssembly(reportDocTypeEnum , xmlString);

        log.info("天津上报报文请求 -> {}, {}, {}", tianjinReportModel.getIpcType(),
                tianjinReportModel.getMessageReferenceNumber(), xmlString);
        if (ObjectUtil.isNotEmpty(tianjinReportModel)) {
            //发送报文
            String url = this.tjReportPlatformDomain + TianjinReportConstant.SEND_URL;
            String sendResult = HttpUtil.post(url, JSONUtil.toJsonStr(tianjinReportModel));
            log.info("天津上报报文回执 <- {}", sendResult);

            if (StringUtils.isNotEmpty(sendResult)) {
                ResultDTO result = JSONUtil.toBean(sendResult, ResultDTO.class, true);
                return result;
            }
        }

        return null;
    }

}
